package com.okhttp.retrofit.mock;

import android.annotation.SuppressLint;
import com.okhttp.utils.RetrofitLog;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.charset.Charset;

import okhttp3.MediaType;
import okhttp3.ResponseBody;
import retrofit2.Retrofit;
//import retrofit2.HttpServiceMethod;
//$CallAdapted

/**
 * @param <T> Mock Handler
 * @author YLG
 */
final class MockerHandler<T> implements InvocationHandler {

  private Retrofit retrofit;
  private T apiService;

  public MockerHandler(Retrofit retrofit, T apiService) {
    this.retrofit = retrofit;
    this.apiService = apiService;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    RetrofitLog.d("MockerHandler", "MockerHandler invoke>>>");
    boolean isMockExist = method.isAnnotationPresent(Mock.class);
    //如果注解不存在 正常走流程
    if (!isMockExist) {
      RetrofitLog.d("MockerHandler"," service invoke >>> ");
      return invoke(method, args);
    }

    Mock mock = method.getAnnotation(Mock.class);
    //如果mock 设置为false 正常返回
    if (!mock.enable()) {
      RetrofitLog.d("MockerHandler"," service invoke >>> ");
      return invoke(method, args);
    }

    String value = mock.value().trim();
    //如果http开头 替换成url 正常请求
    if (value.startsWith("http")) {
      preLoadServiceMethod(method, value);
      return invoke(method, args);
    } else if (value.endsWith(".json")) {
      String mockResponseJson = readAssets(value);
      Object responseObj = retrofit.nextResponseBodyConverter(null, getReturnTye(method), method.getDeclaredAnnotations()).convert(ResponseBody.create(MediaType.parse("application/json"), mockResponseJson));
      return (retrofit.nextCallAdapter(null, method.getGenericReturnType(), method.getAnnotations())).adapt(new MockerCall(responseObj));
    } else { //其他情况正常请求
      return invoke(method, args);
    }
  }

  private Object invoke(Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
    if (args == null) {
      return method.invoke(apiService);
    } else {
      return method.invoke(apiService, args);
    }
  }

  private Type getReturnTye(Method method) {
    return ((ParameterizedType) (method.getGenericReturnType())).getActualTypeArguments()[0];
  }

  //修改url地址
  private void preLoadServiceMethod(Method method, String relativeUrl) {
    try {
      Method loadServiceMethod = retrofit.getClass().getDeclaredMethod("loadServiceMethod", Method.class);
      loadServiceMethod.setAccessible(true);
      //获得serviceMethod的值
      Object serviceMethod = loadServiceMethod.invoke(retrofit, method);
      //反射修改实体类中的值
      //fixRetrofit240(serviceMethod, relativeUrl);
      fixRetrofit250(serviceMethod, relativeUrl);
    } catch (Exception e) {
      RetrofitLog.e("MockHandler",e.getMessage(),e);
    }
  }

  //针对retrofit 2.4.0版本做适配
  private void fixRetrofit240(Object serviceMethod, String relativeUrl) {
    try {
      Field relativeUrlField = serviceMethod.getClass().getDeclaredField("relativeUrl");
      relativeUrlField.setAccessible(true);
      relativeUrlField.set(serviceMethod, relativeUrl);
    } catch (Exception e) {
      RetrofitLog.e("MockHandler-fixRetrofit240",e.getMessage(),e);
    }
  }

  //针对retrofit 2.5.0版本做适配
  private void fixRetrofit250(Object serviceMethod, String relativeUrl) {
    Field requestFactoryField=null;
    try {
      requestFactoryField = serviceMethod.getClass().getDeclaredField("requestFactory");
    } catch (NoSuchFieldException e) {
      //2.8.1版本适配
      try {
        requestFactoryField = serviceMethod.getClass().getSuperclass().getDeclaredField("requestFactory");
      } catch (NoSuchFieldException p) {
      }
    }
    try {
      requestFactoryField.setAccessible(true);
      Object requestFactory = requestFactoryField.get(serviceMethod);
      fixRetrofit240(requestFactory,relativeUrl);
    } catch (Exception e) {
      RetrofitLog.e("MockHandler-fixRetrofit250",e.getMessage(),e);
    }
  }

  private void fixRetorfit281(Object serviceMethod, String relativeUrl){

  }

  //读取文件
  @SuppressLint("NewApi")
  private String readAssets(String fileName) {
    try {
      InputStream is = this.getClass().getResourceAsStream("/assets/" + fileName.trim());
      int size = is.available();
      byte[] buffer = new byte[size];
      is.read(buffer);
      is.close();
      return new String(buffer, Charset.forName("utf-8"));
    } catch (Exception e) {
      RetrofitLog.e("MockHandler",e.getMessage(),e);
    }
    return "读取错误，请检查文件名";
  }

}